package com.romadan.core.nonlinearanalys.fet.volterra;

import java.util.Map;

import com.romadan.core.nonlinearanalys.fet.volterra.logic.EdgeType;
import com.romadan.core.nonlinearanalys.fet.volterra.logic.GraphType;
import com.romadan.core.nonlinearanalys.fet.volterra.logic.NLParameters;
import com.romadan.core.nonlinearanalys.fet.volterra.uzlovanalysis.UzlovAnalysis;
import com.romadan.general.settings.ProjectState;
import com.romadan.utils.UnitConversions;
import com.romadan.utils.math.Complex;
import com.romadan.utils.math.GaussMethod;

public class ModelParameters {
	private NLParameters nlp;
	private GraphType graph;
	private ProjectState pstate = new ProjectState();
	private Map<String, Object> data;
	private Complex vout_2_w1 = null, vout_2_w2 = null, vout_3_w1 = null, vout_3_w2 = null, vout_2_w12 = null;
	private double am1, am2, freq1, freq2;

	public ModelParameters(GraphType graph, Map<String, Object> data) {
		nlp = new NLParameters();
		this.graph = graph;
		this.data = data;
		
		init();
	}
	
	public NLParameters getParameters() {
		return nlp;
	}
	
	private void init() {
		parseParameters();
//		calcParametersForCurrent();
//		calcParametersForCapacity();
		getTempParameters();
	}

	private void parseParameters() {
		if (data != null) {
			am1 = (Double) data.get("am1");
			am2 = (Double) data.get("am2");
			freq1 = (Double) data.get("freq1");
			freq2 = (Double) data.get("freq2");
			vout_2_w1 = (Complex) data.get("vout12");
			vout_2_w2 = (Complex) data.get("vout22");
			vout_3_w1 = (Complex) data.get("vout13");
			vout_3_w2 = (Complex) data.get("vout23");
			vout_2_w12 = (Complex) data.get("vout122");
		} else {
			System.out.println("data is empty");
		}
	}
	
	private void calcParametersForCurrent() {
		UzlovAnalysis analys = null;
		
		if (graph != null) {
			Complex Kg1, Kd1, Kg2, Kd2, Kload1, Kload2, Kload12;
			Complex Vs = new Complex(am1, 0);
			Complex Vl = new Complex(am2, 0);
			freq1 = UnitConversions.frequencyLinearToCyclic(freq1, "mega", "giga");
			freq2 = UnitConversions.frequencyLinearToCyclic(freq2, "mega", "giga");

			// calculate Kg and Kd coefficients
			EdgeType inEdge = graph.getEdgeById(1);
			EdgeType outEdge = graph.getEdgeById(16);

			inEdge.setE_source(Complex.ONE);
			outEdge.setE_source(Complex.ZERO);
			analys = new UzlovAnalysis(graph, freq1);
			Kg1 = analys.getGraphWithVoltages().getEdgeById(5 /* Cgs */)
					.getVoltage();
			System.out.println("Kg1 = " + Kg1.toString());

			Kd1 = analys.getGraphWithVoltages().getEdgeById(12 /* Cds */)
					.getVoltage();
			System.out.println("Kd1 = " + Kd1.toString());

			inEdge.setE_source(Complex.ZERO);
			outEdge.setE_source(Complex.ONE);
			analys = new UzlovAnalysis(graph, freq2);
			Kg2 = analys.getGraphWithVoltages().getEdgeById(5 /* Cgs */)
					.getVoltage();
			System.out.println("Kg2 = " + Kg2.toString());

			Kd2 = analys.getGraphWithVoltages().getEdgeById(12 /* Cds */)
					.getVoltage();
			System.out.println("Kd2 = " + Kd2.toString());

			// calculate Kload coefficients
			EdgeType itun = graph.getEdgeById(10 /* IV */);
			inEdge.setE_source(Complex.ZERO);
			outEdge.setE_source(Complex.ZERO);
			itun.setI_source(Complex.ONE);
			analys = new UzlovAnalysis(graph, 2 * freq1);
			Kload1 = analys
					.getGraphWithVoltages()
					.getNodeById(0)
					.getVoltage()
					.minus(analys.getGraphWithVoltages().getNodeById(9)
							.getVoltage());
			System.out.println("Kload1 = " + Kload1.toString());

			analys.setFrequency(2 * freq2);
			Kload2 = analys
					.getGraphWithVoltages()
					.getNodeById(0)
					.getVoltage()
					.minus(analys.getGraphWithVoltages().getNodeById(9)
							.getVoltage());
			System.out.println("Kload2 = " + Kload2.toString());
			
			Kload12 = Complex.ONE;

			nlp = new NLParameters();
			// forming system of equations
			Complex[][] system = null;
			// calculate second order coefficients
			if (!pstate.isCalcCrossCoefficients()) {
				system = new Complex[2][3];
				system[0][0] = ((Vs.pow(2)).div(Complex.TWO)).mul(Kg1.pow(2));
				system[0][1] = ((Vs.pow(2)).div(Complex.TWO)).mul(Kd1.pow(2));
				system[0][2] = vout_2_w1.div(Kload1);
			
				system[1][0] = (Vl.pow(2).div(Complex.TWO)).mul(Kg2.pow(2));
				system[1][1] = (Vl.pow(2).div(Complex.TWO)).mul(Kd2.pow(2));
				system[1][2] = vout_2_w2.div(Kload2);
			} else {
				system = new Complex[3][4];
				system[0][0] = ((Vs.pow(2)).div(Complex.TWO)).mul(Kg1.pow(2));
				system[0][1] = (Vs.pow(2)).div(Complex.TWO).mul(Kg1).mul(Kd1);
				system[0][2] = ((Vs.pow(2)).div(Complex.TWO)).mul(Kd1.pow(2));
				system[0][2] = vout_2_w1.div(Kload1);
				
				system[1][0] = (Vs.mul(Vl)).mul(Kg1).mul(Kg2);
				system[1][1] = (Vs.mul(Vl)).div(Complex.TWO).mul(Kg1.mul(Kd2).plus(Kg2.mul(Kd1)));
				system[1][2] = (Vs.mul(Vl)).mul(Kd1).mul(Kd2);
				system[1][3] = vout_2_w12.div(Kload12);
				
				system[2][0] = (Vl.pow(2).div(Complex.TWO)).mul(Kg2.pow(2));
				system[2][1] = (Vl.pow(2).div(Complex.TWO)).mul(Kg2.mul(Kd2));
				system[2][2] = (Vl.pow(2).div(Complex.TWO)).mul(Kd2.pow(2));
				system[2][3] = vout_2_w2.div(Kload2);
			}
			
			Complex[] second_coefficients = GaussMethod.execute(system);
			if (second_coefficients.length == 2) {
			nlp.setGm2(second_coefficients[0]);
			nlp.setGd2(second_coefficients[1]);
			} else if (second_coefficients.length == 3) {
				nlp.setGm2(second_coefficients[0]);
				nlp.setGmd(second_coefficients[1]);
				nlp.setGd2(second_coefficients[2]);
			}
			
			// calculate third order coefficients
			if (pstate.getmOrder() == 3) {
				system = new Complex[2][3];
				system[0][0] = (Vs.pow(3)).div(Complex.FOUR).mul(Kg1.pow(3));
				system[0][1] = (Vs.pow(3)).div(Complex.FOUR).mul(Kd1.pow(3));
				system[0][2] = vout_3_w1.div(Kload1);
				
				system[1][0] = (Vl.pow(3)).div(Complex.FOUR).mul(Kg2.pow(3));
				system[0][1] = (Vl.pow(3)).div(Complex.FOUR).mul(Kd2.pow(3));
				system[0][2] = vout_3_w2.div(Kload2);
				
				Complex[] third_coefficients = GaussMethod.execute(system);
				nlp.setGm3(third_coefficients[0]);
				nlp.setGd3(third_coefficients[1]);
			}
		} else {
			System.out.println("Error: graph is null!");
		}
	}
	
	private void calcParametersForCapacity() {
		// there will be methodic for calculate coefficients of capacity Cgs
	}
	
	private void getTempParameters() {
		Complex gm2 = new Complex(0.0007183586769821, -0.000466234501);
		Complex gm3 = new Complex(-0.0004841137994987, 0.0000234053);
		Complex gd2 = new Complex(-0.00201063912786, 0);
		Complex gd3 = new Complex(0.00035765478124, -0.00015043534);
		Complex gmd = new Complex(0.00888974121533, -0.0013104603);
		Complex cgs2 = new Complex(0.51756991411E-12, 0);
		Complex cgs3 = new Complex(0.08157563221E-12, 0);
		
		nlp.setGm2(gm2);
		nlp.setGm3(gm3);
		nlp.setGd2(gd2);
		nlp.setGd3(gd3);
		nlp.setGmd(gmd);
		nlp.setCgs2(cgs2);
		nlp.setCgs3(cgs3);
	}
}